#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <assert.h>

#include "msg.h"

void msg_head_h2n(struct MSG_HEAD * head)
{
	head->packlen = htonl(head->packlen);
	head->msgid = htonl(head->msgid);
	head->msgtype = htonl(head->msgtype);
}

void msg_head_n2h(struct MSG_HEAD * head)
{
	head->packlen = ntohl(head->packlen);
	head->msgid = ntohl(head->msgid);
	head->msgtype = ntohl(head->msgtype);
}

//pack decode. return <0 means malform, set headlen & packlen & scode
int msg_depack(const char * buf, int buflen, int * headlenp, int * packlenp, int *scodep)
{
	assert(buf && headlenp && packlenp);

	if (buflen < MSG_HEAD_LEN) return 1;

	*headlenp = MSG_HEAD_LEN;
	*packlenp = ntohl(((MSG_HEAD *)(buf))->packlen);
	*scodep = ntohl(((MSG_HEAD *)(buf))->msgtype);
	return 0;
}

void msg_hex(const char * buf, int buflen)
{
	assert(buf && buflen > 0);

	int i;
	for(i=0; i<buflen; i++){
		if(!(i%16)) fprintf(stderr, i==0?"%04d:\t":"\n%04d:\t", i);
		else if(!(i%4)) fprintf(stderr, "\t");
		fprintf(stderr, "%02x ", buf[i]);
	}
	fprintf(stderr, "\n");
	return;
}

/* -------------------   LOAD_REQ   ------------------- */
void msg_load_item_h2n(struct MSG_LOAD_ITEM * item)
{
	item->ulen = htons(item->ulen);
	item->clen = htons(item->clen);
}

void msg_load_item_n2h(struct MSG_LOAD_ITEM * item)
{
	item->ulen = ntohs(item->ulen);
	item->clen = ntohs(item->clen);
}

void msg_load_req_h2n(struct MSG_LOAD_REQ * body)
{
	body->num = htons(body->num);
}

void msg_load_req_n2h(struct MSG_LOAD_REQ * body)
{
	body->num = ntohs(body->num);
}

char * msg_load_req_new(int * buflenp, int num, const LOAD_PARAM * params)
{
	assert(num && params);

	int vlen = 0;
	int i;
	for (i = 0; i < num; i ++) {
		vlen += params[i].ulen;
		vlen += params[i].clen;
		if (vlen & 1) {vlen ++;}
	}

	*buflenp = MSG_HEAD_LEN + sizeof(uint16_t) + 
				sizeof(struct MSG_LOAD_ITEM) * num + vlen;

	char * buf = malloc(*buflenp);
	if (!buf) {
		return NULL;
	}

	MSG_HEAD * head = (MSG_HEAD *)buf;
	head->msgid = 1;
	head->msgtype = TYPE_LOAD_REQ;
	head->packlen = *buflenp;
	msg_head_h2n(head);

	MSG_LOAD_REQ * body = (MSG_LOAD_REQ *)(buf + MSG_HEAD_LEN);
	body->num = num;
	msg_load_req_h2n(body);

	MSG_LOAD_ITEM * item = (MSG_LOAD_ITEM *)body->vbuf;

	for (i = 0; i < num; i ++) {
		item->ulen = params[i].ulen;
		item->clen = params[i].clen;
		memcpy(item->addr, params[i].addr, MSG_IPADDR_SIZE);
		memcpy(item->vbuf, params[i].url, item->ulen);
		memcpy(item->vbuf+item->ulen, params[i].cookie, item->clen);
		msg_load_item_h2n(item);

		vlen = item->ulen + item ->clen;
		if (vlen & 1) {vlen ++;}
		item = (void * )item + sizeof(struct MSG_LOAD_ITEM) + vlen;
	}
	return buf;
}

#ifdef MSG_MAIN
int main()
{
	char * url = "http://www.baidu.com/";
	int buflen;
	LOAD_PARAM param = {strlen(url), 0, "192.168.12.98", url, NULL};
	char * buf = msg_load_req_new(&buflen, 1, &param);
	msg_hex(buf, buflen);
	return 0;
}
#endif

